﻿using System;
using System.Windows.Forms;
using SlimDX.Direct3D9;

namespace RaygunDiplomacy.Graphics
{
   public class GraphicsProvider
   {
      #region Fields

      static GraphicsProvider instance = new GraphicsProvider();

      Form form;

      SlimDX.Direct3D9.Direct3D direct3D;

      SlimDX.Direct3D9.Direct3DEx direct3DEx;

      SlimDX.Direct3D9.Device device;

      SlimDX.Direct3D9.DeviceEx deviceEx;

      bool isVistaOr7 = false;

      #endregion

      #region Properties

      public static GraphicsProvider Instance
      {
         get
         {
            return instance;
         }
      }

      public SlimDX.Direct3D9.Direct3D Direct3D
      {
         get { return direct3D; }
      }

      public SlimDX.Direct3D9.Direct3DEx Direct3DEx
      {
         get { return direct3DEx; }
      }

      public SlimDX.Direct3D9.Device Device
      {
         get { return device; }
      }

      public SlimDX.Direct3D9.DeviceEx DeviceEx
      {
         get { return deviceEx; }
      }

      public bool IsVistaOr7
      {
         get { return isVistaOr7; }
      }

      #endregion

      #region Events

      #endregion

      #region Constructor

      private GraphicsProvider()
      {
         OperatingSystem os = Environment.OSVersion;

         if (os.Platform == PlatformID.Win32NT && os.Version.Major >= 6)
         {
            isVistaOr7 = true;
         }
      }

      #endregion

      #region Methods

      public void Initialize()
      {
         if (form == null)
         {
            form = new Form();

            form.Width = 0;
            form.Height = 0;
         }

         IntPtr windowHandle = form.Handle;

         PresentParameters presentParameters = new SlimDX.Direct3D9.PresentParameters();

         presentParameters.Windowed = true;
         presentParameters.BackBufferFormat = Format.Unknown;
         presentParameters.BackBufferWidth = 1;
         presentParameters.BackBufferHeight = 1;
         presentParameters.SwapEffect = SwapEffect.Discard;

         int adapter = 0;
         SlimDX.Direct3D9.DeviceType deviceType = SlimDX.Direct3D9.DeviceType.Hardware;
         SlimDX.Direct3D9.CreateFlags flags = SlimDX.Direct3D9.CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve;

         if (isVistaOr7)
         {
            try
            {
               direct3DEx = new SlimDX.Direct3D9.Direct3DEx();
               deviceEx = new SlimDX.Direct3D9.DeviceEx(direct3DEx, adapter, deviceType, windowHandle, flags, presentParameters);
               direct3D = direct3DEx;
               device = deviceEx;
            }
            catch (Exception e)
            {
               Console.WriteLine(e.ToString());
               throw e;
            }
         }
         else
         {
            direct3DEx = null;
            deviceEx = null;
            direct3D = new SlimDX.Direct3D9.Direct3D();
            device = new SlimDX.Direct3D9.Device(direct3D, adapter, deviceType, windowHandle, flags, presentParameters);
         }

         SpriteDrawer.Reset();
      }

      public void TearDown()
      {
         
      }

      public Surface CreateDepthStencil(int width, int height, Format format, MultisampleType multisampleType, int multisampleQuality, bool discard, Usage usage)
      {
         Surface surface = null;

         if (isVistaOr7)
         {
            surface = Surface.CreateDepthStencilEx(this.deviceEx, width, height, format, multisampleType, multisampleQuality, discard, usage);
         }
         else
         {
            surface = Surface.CreateDepthStencil(this.device, width, height, format, multisampleType, multisampleQuality, discard);
         }

         return surface;
      }

      public Surface CreateRenderSurface(int width, int height)
      {
         if (width == 0 || height == 0)
         {
            throw new ArgumentException("Width and Height must be greater than 0");
         }
         if (this.isVistaOr7)
         {
            return Surface.CreateRenderTargetEx(this.deviceEx, width, height, Format.X8R8G8B8, MultisampleType.None, 0, false, Usage.None);
         }
         else
         {
            return Surface.CreateRenderTarget(this.device, width, height, Format.X8R8G8B8, MultisampleType.None, 0, true);
         }
      }

      public Surface CreateDepthSurface(int width, int height)
      {
         return Surface.CreateDepthStencil(this.device, width, height, Format.D16, MultisampleType.None, 0, true);
      }

      #endregion
   }
}
